# 优点
# 代码复用性
# 装饰器可以将通用逻辑（如日志、计时、权限检查）抽离成独立模块，避免重复代码。

# 非侵入式修改
# 无需修改原函数代码即可添加功能，符合开闭原则（对扩展开放，对修改封闭）。

# 清晰的可读性
# 通过 @decorator 语法显式标记功能，代码意图更直观（例如 @cache 表示缓存）。

# 灵活组合
# 支持多层装饰器，按需叠加功能（如 @auth @log @timing）。

# 解耦核心逻辑与辅助功能
# 例如将业务逻辑与日志、性能监控等横切关注点分离。



# 缺点
# 调试复杂性
# 装饰器会改变函数的元信息（如 __name__、__doc__），需用 functools.wraps 修复，否则调试困难。

# 性能开销
# 每层装饰器会引入额外的函数调用，对性能敏感的场景需谨慎（可通过闭包优化）。

# 隐式行为
# 过度使用装饰器可能导致代码行为难以追踪，尤其是多层嵌套时。

# 学习曲线
# 对初学者来说，理解闭包、函数作为一等对象等概念是前提。

# 限制场景
# 装饰器通常用于函数或类方法，直接装饰类时可能需改用元类。


def my_decorator(func):
    def wrapper():
        print("函数执行前...")
        func()  # 调用原函数
        print("函数执行后...")
    return wrapper

# 使用装饰器
@my_decorator
def say_hello():
    print("Hello!")

def do():
    say_hello()
    

class Type_b:
    def my_decorator(self, func):
        def wrapper():
            print("函数执行前...")
            func()  # 调用原函数
            print("函数执行后...")
        return wrapper

    def say_hello(self):
        print("Hello!")

    def do(self):
        say_hello = self.my_decorator(self.say_hello)
        say_hello()


def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

# 带参数的装饰器,需要嵌套两层函数：
@repeat(3)
def greet():
    print("greet!")


class CountCalls:
    def __init__(self, func):
        self.func = func
        self.calls = 0

    # 通过实现 __call__ 方法使类成为装饰器：
    def __call__(self, *args, **kwargs):
        self.calls += 1
        print(f"函数被调用了 {self.calls} 次")
        return self.func(*args, **kwargs)
    
    def __name__(self):
        return "CountCalls__name"

    def __doc__(self):
        return "CountCalls__doc"
    

@CountCalls
def example():
    print("example!")


# 使用 functools.wraps 避免装饰器覆盖原函数的元信息（如 __name__、__doc__）：
"""
1. 调试友好：如果装饰器导致函数名变成 wrapper，调试日志或错误堆栈会难以追踪原始函数
2. 文档工具依赖： 像 help() 或 Sphinx 等文档生成工具会读取 __doc__，如果丢失会影响文档生成。
3. 反射和自省：某些库（如 Flask、FastAPI）依赖函数的 __name__ 或 __annotations__ 进行路由或类型检查
"""
from functools import wraps
def my_decorator_b(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper


@my_decorator_b
def wraps_fun():
    print("wraps_fun")


if __name__ == "__main__":
    do()
    print("----do---> ", do.__name__, do.__doc__)

    Type_b().do()
    """
    @decorator
    等价于
    fun = d_fun(fun)
    """

    greet()
    print("---greet----> ", greet.__name__, greet.__doc__)

    example()
    example()
    example()

    print("---example----> ", example.__name__, example.__doc__)

    wraps_fun()
    print("----wraps_fun---> ", wraps_fun.__name__, wraps_fun.__doc__)
